package logger

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"strings"
)

var Log *Logger

func init() {
	Log, _ = NewSimpleLogger(DefaultSimpleLogConfig)
}

// LogLevel 定义日志级别
type LogLevel int

// 日志级别常量
const (
	LevelTrace LogLevel = iota
	LevelDebug
	LevelInfo
	LevelSuccess
	LevelWarning
	LevelError
	LevelCritical
	LevelFatal
)

// levelConfig 存储每个日志级别的配置
type levelConfig struct {
	name      string // 日志级别名称
	exitAfter bool   // 是否在记录后退出
}

// levelMapConfig 日志级别配置映射
var levelMapConfig = map[LogLevel]levelConfig{
	LevelTrace:    {"TRACE", false},    // Trace
	LevelDebug:    {"DEBUG", false},    // Debug
	LevelInfo:     {"INFO", false},     // Info
	LevelSuccess:  {"SUCCESS", false},  // Success
	LevelWarning:  {"WARNING", false},  // Warning
	LevelError:    {"ERROR", false},    // Error
	LevelCritical: {"CRITICAL", false}, // Critical
	LevelFatal:    {"FATAL", false},     // Fatal
}

// levelAbbreviations 定义每个级别的不同长度缩写
var levelAbbreviations = [][]string{
	// Trace
	{"T", "Tr", "Trc", "Trce", "Trace"},
	// Debug
	{"D", "De", "Dbg", "Dbug", "Debug"},
	// Info
	{"I", "In", "Inf", "Info"},
	// Success
	{"S", "Su", "Suc", "Succ", "Succs", "Success"},
	// Warning
	{"W", "Wn", "Wrn", "Warn", "Warng", "Warning"},
	// Error
	{"E", "Er", "Err", "Erro", "Error"},
	// Critical
	{"C", "Cr", "Crt", "Crit", "Critl", "Critical"},
	// Fatal
	{"F", "Fa", "Ftl", "Fatl", "Fatal"},
}

// LogWriter 定义日志写入接口
// LogWriter 定义了日志写入器的接口
type LogWriter interface {
	// Write 写入一条日志记录
	// @param level: 日志级别
	// @param caller: 调用者信息
	// @param msg: 日志消息内容
	// @return error 写入过程中的错误(如果有)
	Write(level LogLevel, caller string, msg string) error

	// Open 打开日志写入器
	Open() error

	// Close 关闭日志写入器并释放相关资源
	// @return error 关闭过程中的错误(如果有)
	Close() error
}

// LogConfig 日志配置
type LogConfig struct {
	Level    LogLevel    // 日志级别
	CallSkip int         // 调用栈跳过层数
	Writers  []LogWriter // 输出配置
}

// DefaultOutputTemplate 默认输出模板
const DefaultOutputTemplate = "{timestamp:yyyy-MM-dd HH:mm:ss.SSS} [{level}] {caller}: {message}{newline}"

// Logger 日志记录器
type Logger struct {
	level    LogLevel    // 日志级别
	writers  []LogWriter // 输出目标列表
	mu       sync.Mutex  // 互斥锁
	callSkip int         // 调用栈跳过层数
}

// NewLogger 创建新的日志记录器
func NewLogger(config LogConfig) (*Logger, error) {
	logger := &Logger{
		level:    config.Level,
		writers:  config.Writers,
		callSkip: config.CallSkip,
	}

	for _, writer := range config.Writers {
		if err := writer.Open(); err != nil {
			return nil, fmt.Errorf("打开日志写入器失败: %v", err)
		}
	}

	return logger, nil
}

type SimpleLogConfig struct {
	EnableConsole  bool     // 是否启用控制台输出
	EnableFile     bool     // 是否启用文件输出
	OutputTemplate string   // 日志输出模板
	LogLevel       LogLevel // 日志级别
	LogPath        string   // 日志文件路径,仅在EnableFile=true时有效
}

// DefaultSimpleLogConfig 默认简单日志配置
var DefaultSimpleLogConfig = SimpleLogConfig{
	EnableConsole:  true,
	EnableFile:     true,
	OutputTemplate: DefaultOutputTemplate,
	LogLevel:       LevelTrace,
	LogPath:        "logs/app_{timestamp:yyyyMMddHH}.log",
}

// NewSimpleLogger 创建一个简单的日志记录器
func NewSimpleLogger(config SimpleLogConfig) (*Logger, error) {
	// 构建日志写入器列表
	var writers []LogWriter

	// 添加控制台写入器
	if config.EnableConsole {
		consoleWriter, err := NewConsoleWriter(true, config.OutputTemplate)
		if err != nil {
			return nil, fmt.Errorf("创建控制台写入器失败: %w", err)
		}

		writers = append(writers, consoleWriter)
	}

	// 添加文件写入器
	if config.EnableFile {
		// 创建文件轮转配置
		rotateConfig := &RotateConfig{
			Enabled: true,
			Mode:    RotateDaily,
		}

		// 创建文件写入器
		fileWriter, err := NewFileWriter(config.LogPath, config.OutputTemplate, rotateConfig, 1000, true)
		if err != nil {
			return nil, fmt.Errorf("创建文件写入器失败: %w", err)
		}
		writers = append(writers, fileWriter)
	}

	// 创建日志配置
	logConfig := LogConfig{
		Level:    config.LogLevel,
		Writers:  writers,
		CallSkip: 2,
	}

	return NewLogger(logConfig)
}

// log 通用日志记录方法
func (l *Logger) log(level LogLevel, format string, args ...interface{}) {
	if level < l.level {
		return
	}

	l.mu.Lock()
	defer l.mu.Unlock()

	// 获取调用者信息
	_, file, line, ok := runtime.Caller(l.callSkip)
	caller := "???"
	if ok {
		caller = fmt.Sprintf("%s:%d", filepath.Base(file), line)
	}

	// 格式化消息
	msg := fmt.Sprintf(format, args...)

	// 写入所有输出器
	for _, writer := range l.writers {
		if err := writer.Write(level, caller, msg); err != nil {
			fmt.Fprintf(os.Stderr, "写入日志失败: %v\n", err)
		}
	}

	// 如果是致命错误，记录后退出
	if levelMapConfig[level].exitAfter {
		l.Close()
		os.Exit(1)
	}
}

// Close 关闭日志记录器
func (l *Logger) Close() error {
	var errs []error
	for _, writer := range l.writers {
		if err := writer.Close(); err != nil {
			errs = append(errs, err)
		}
	}

	if len(errs) > 0 {
		return fmt.Errorf("关闭日志记录器时发生错误: %v", errs)
	}
	return nil
}

// 提供各个日志级别的方法

// Trace 记录跟踪日志
func (l *Logger) Trace(format string, args ...interface{}) { l.log(LevelTrace, format, args...) }

// Debug 记录调试日志
func (l *Logger) Debug(format string, args ...interface{}) { l.log(LevelDebug, format, args...) }

// Info 记录信息日志
func (l *Logger) Info(format string, args ...interface{}) { l.log(LevelInfo, format, args...) }

// Success 记录成功日志
func (l *Logger) Success(format string, args ...interface{}) { l.log(LevelSuccess, format, args...) }

// Warning 记录警告日志
func (l *Logger) Warning(format string, args ...interface{}) { l.log(LevelWarning, format, args...) }

// Error 记录错误日志
func (l *Logger) Error(format string, args ...interface{}) { l.log(LevelError, format, args...) }

// Critical 记录严重错误日志
func (l *Logger) Critical(format string, args ...interface{}) { l.log(LevelCritical, format, args...) }

// Fatal 记录致命错误日志,记录后退出
func (l *Logger) Fatal(format string, args ...interface{}) { l.log(LevelFatal, format, args...) }

// String 返回日志级别的字符串表示
func (l LogLevel) String() string {
	if cfg, ok := levelMapConfig[l]; ok {
		return cfg.name
	}
	return "UNKNOWN"
}

// Format 返回指定长度的日志级别缩写
func (l LogLevel) Format(width int) string {
	if l < LevelTrace || l > LevelFatal {
		return "UNKNOWN"
	}

	abbrs := levelAbbreviations[int(l)]
	if width <= 0 {
		return strings.ToUpper(abbrs[len(abbrs)-1]) // 返回完整名称
	}

	if width > len(abbrs) {
		width = len(abbrs)
	}
	return strings.ToUpper(abbrs[width-1])
}
